package org.game.module.datingbo.trigger;

import com.google.common.collect.Maps;
import com.sojoys.artifact.tools.ToolMap;
import com.xiaoleilu.hutool.util.RandomUtil;
import org.cfg.DatingRuleCfg;
import org.cfg.cache.DiscreteDataCfgCache;
import org.constant.DatingConstant;
import org.constant.DiscreteDataID;
import org.constant.DiscreteDataKey;
import org.game.constant.DatingTypeConstant;
import org.game.db.bean.*;
import org.game.db.cache.CityCache;
import org.game.db.cache.CityDatingRecordCache;
import org.game.db.cache.PlayerDataCache;
import org.game.db.cache.RoleCache;
import org.game.db.proxy.bean.PlayerDataProxy;
import org.game.manager.PlayerManager;
import org.game.module.datingbo.DatingBO;
import org.game.module.datingbo.DatingType;
import org.game.msgBuilder.DatingMsgBuilder;
import org.game.protobuf.s2c.S2CShareMsg;
import org.utils.TimeUtil;

import java.util.*;

/**
 * 城市约会触发器
 * Created by fxf on 2018-3-15.
 */
public abstract class AbstractCityDatingTrigger implements CityDatingTrigger {

    /**
     * 检查今日当前时段是否已经触发约会
     *
     * @param player
     * @param timeFrame 时间段
     * @return
     */
    boolean alreadyTrigger(Player player, List<Integer> timeFrame) {
        PlayerData pd = PlayerDataCache.me().getByPlayerId(player.getId());
        Map<Integer, Long> triggerTime = pd.getPlayerDataProxy().getCityDatingTime();
        long time = ToolMap.getLong(getDatingType(), triggerTime, 0);
        if (time != 0) {
            Calendar beginTime = TimeUtil.getCalendarByHourMinute(timeFrame.get(0), timeFrame.get(1));
            Calendar endTime = TimeUtil.getCalendarByHourMinute(timeFrame.get(2), timeFrame.get(3));
            if (beginTime.getTimeInMillis() <= time && endTime.getTimeInMillis() >= time) {
                return true;
            }
        }
        return false;
    }

    /**
     * 筛选约会
     */
    boolean filtrateDating(Player player, List<DatingRuleCfg> datingRuleCfgList, Map<String, List<Integer>> timeFrame,Date now) {
        for (DatingRuleCfg datingRuleCfg : datingRuleCfgList) {
            if (checkDatingTriggerRate(player, datingRuleCfg)) {
                CityDatingRecord record = createCityDatingRecord(player, datingRuleCfg, timeFrame,now);
                updatePlayerInfo(player);
                updateCity(player, datingRuleCfg);
                updateRole(player, datingRuleCfg);
                sendDating(player, record);
                return true;
            }
        }
        return false;
    }

    /**
     * 创建城市约会记录
     *
     * @param player
     * @param datingRuleCfg
     */
    CityDatingRecord createCityDatingRecord(Player player, DatingRuleCfg datingRuleCfg, Map<String, List<Integer>> timeFrame,Date now) {
        CityDatingRecord record = new CityDatingRecord(0l, player.getId(), datingRuleCfg.getId(), datingRuleCfg.getEnterCondtionByType(DatingConstant.ENTER_CDTION_KEY_CITY_CID), datingRuleCfg.getType(), Maps.newHashMap());
        record.getCityDatingRecordProxy().setTriggerTime(now);
        record.insert();
        return record;
    }

    /**
     * 增加城市约会次数
     */
    void addCityDatingCount(Player player, List<Integer> roleIdList) {
        Role role;
        for (Integer roleCid : roleIdList) {
            role = RoleCache.me().getByCidPlayerId(roleCid, player.getId());
            role.getRoleProxy().addCityDatingCount();
            role.update();
        }
    }

    /**
     * 校验触发几率
     * 1.乱入约会只校验约会几率
     * 2.单人约会不仅校验约会几率，还要校验看板娘的几率(逐次递减的几率)
     */
    boolean checkDatingTriggerRate(Player player, DatingRuleCfg datingRuleCfg) {
        int limit = 100;
        int random;
        if (datingRuleCfg.getEnterCondition().get(DatingConstant.ENTER_CDTION_KEY_ROLE_CIDS) == null) {
            return false;
        }
        //加入固定触发概率，固定触发概率通过以后再进行衰减率随机校验
        random = RandomUtil.randomInt(limit);
        if (random > DiscreteDataCfgCache.me().getIntData(DiscreteDataID.DATING,DiscreteDataKey.CITY_DATING_TRIGGER_RATE)){
            return false;
        }
        int roleCid = (int) ((List) datingRuleCfg.getEnterCondition().get(DatingConstant.ENTER_CDTION_KEY_ROLE_CIDS)).get(0);
        Role role = RoleCache.me().getByCidPlayerId(roleCid, player.getId());
        random = RandomUtil.randomInt(limit);
        if (random < getTriggerRate(role, datingRuleCfg)) {
            return true;
        }
        return false;
    }


    int getDatingType() {
        DatingType datingType = this.getClass().getAnnotation(DatingType.class);
        return datingType.value();
    }

    /**
     * 更新玩家信息
     */
    void updatePlayerInfo(Player player) {
        PlayerDataProxy pdp = PlayerManager.me().getDataProxy(player);
        Map<Integer, Long> triggerTime = pdp.getCityDatingTime();
        triggerTime.put(getDatingType(), System.currentTimeMillis());
        pdp.save();
    }

    /**
     * 更新建筑信息
     */
    void updateCity(Player player, DatingRuleCfg cfg) {
        int cityCid = cfg.getEnterCondtionByType(DatingConstant.ENTER_CDTION_KEY_CITY_CID);
        City city = CityCache.me().getByCidPlayerId(cityCid, player.getId());
        city.setInDating(true);
        city.update();
    }

    /**
     * 更新看板娘
     */
    void updateRole(Player player, DatingRuleCfg cfg) {
        List<Integer> roleList = (List<Integer>) cfg.getEnterCondition().get(DatingConstant.ENTER_CDTION_KEY_ROLE_CIDS);
        addCityDatingCount(player, roleList);
    }


    void sendDating(Player player, CityDatingRecord record) {
        player.getPlayerProxy().sendMsg(DatingBO.sendCityDating, DatingMsgBuilder.getCityDatingInfo(S2CShareMsg.ChangeType.ADD, record));
    }

    /**
     * 获得衰减几率
     */
    int getDampingRate(Role role) {
        List<Integer> rateList = (List<Integer>) DiscreteDataCfgCache.me().getData(DiscreteDataID.DATING, DiscreteDataKey.DECREASE_RATE);
        return rateList.get(role.getTodayCityDatingCount());
    }

    int getTriggerRate(Role role, DatingRuleCfg datingRuleCfg) {
        return getDampingRate(role);
    }

    CityDatingRecord getReserveDateRecord(Role role) {
        return CityDatingRecordCache.me().getCityDatingRecordCacheProxy().getByPlayerIdDatingTypeRoleCid(role.getPlayerId(), DatingTypeConstant.DATING_TYPE_RESERVE, role.getCid());
    }

    protected void refreshCity(Player player, List<CityDatingRecord> outTimeRecordList) {
        City city;
        for (CityDatingRecord record : outTimeRecordList) {
            city = CityCache.me().getByCidPlayerId(record.getCityCid(),player.getId());
            city.setInDating(false);
            city.update();
        }
    }
}
